<?php
namespace org\crawlgenie\application\path;
use \Logger;
/**
 *  Path Class
 *
 *  @author $Author: jinsonxu@gmail.com $:
 *  $Date: 2014-11-09 22:57:19 +0000 (Sun, 09 Nov 2014) $:
 *  $Id: Path.php 6 2014-11-09 22:57:19Z jinsonxu@gmail.com $:
 *  @version $Rev: 6 $:
 *  @package crawlgenie.application
 *  @subpackage path
 */

//defined('_CGEXEC') or die('Direct access not allowed');

class Path {

    public function __construct() {

    }


    /**
     * Returns the path truncated to the specified level
     * Can also be used for namespaces
     *
     * @param   <string> $path
     * @param   <int>    $levelsUp
     * @return  <string> The truncated path
     *
     * @assert('org\crawlgenie\application\path', 2) == 'org\crawlgenie'
     * @assert('org\crawlgenie\application\path', 3) == 'org'
     * @assert('org\crawlgenie\application\path', 0) == 'org\crawlgenie\application\path'
     */
    public static function getAdjustedPath($path, $levelsUp = 0) {
        $separator = (stripos($path, '/') === false) ? '\\' : '/';
        $explodedArray = explode($separator, $path);
        $newCount = count($explodedArray) - $levelsUp;

        $i = 0;
        while ($i < $levelsUp) {
            array_pop($explodedArray);
            ++$i;
        }

        return implode($separator, $explodedArray);
    }



    /**
     * Clean a path name of extraneous slashes and standardize the slashes to
     * OS specific type.
     * 
     * @static
     * @param   <string>  $rawPath    The raw path to clean
     * @return  <string>  The cleaned path
     *
     * @assert(CG_BASE_PATH . '%2e%2e/') == CG_BASE_PATH . '..' . \DIRECTORY_SEPARATOR
     * @assert(CG_BASE_PATH . '//test1///test2////test3') == CG_BASE_PATH . \DIRECTORY_SEPARATOR . 'test1' . \DIRECTORY_SEPARATOR . 'test2' . \DIRECTORY_SEPARATOR . 'test3'
     */
    public static function getCleanPath($rawPath) {
        $result = trim(urldecode($rawPath));       
        $result = preg_replace('/[\/\\\\]+/', DS, $result);

        return $result;
    }


    /**
     * Check whether path is valid in terms of existing within the
     * application root as well as existance of the file/directory
     * For proper security, open_basedir should be enabled, but
     * we'll also be doing the check here as a backup
     *
     * @static
     * @param   <string>  $rawPath    The raw path to clean
     * @return  <boolean>  True if the path is valid, false if it is not
     *
     * @assert(CG_BASE_PATH) === true
     * @assert(CG_BASE_PATH . DIRECTORY_SEPARATOR . 'conf/CGConfig.php') === true
     * @assert(CG_BASE_PATH . DIRECTORY_SEPARATOR . 'src/../') === true
     * @assert(CG_BASE_PATH . DIRECTORY_SEPARATOR . 'src') === true
     * @assert(CG_BASE_PATH . DIRECTORY_SEPARATOR . '../../trunk/core/lib') === true
     * @assert('../../../../etc/pwd') === false
     * @assert(CG_BASE_PATH . DIRECTORY_SEPARATOR . '../../config.php') === false
     * @assert(CG_BASE_PATH . DIRECTORY_SEPARATOR . '%2e%2e/') === false
     * @assert(CG_BASE_PATH . DIRECTORY_SEPARATOR . '%2e%2e/app_log') === false
     */
    public static function isValidPath($path, $baseAppPath = CG_BASE_PATH) {
        Logger::getLogger(__CLASS__)->info(__METHOD__ . ': path param val: '.$path);
        $result = true;
        $realPath = realpath(self::getCleanPath($path));
        Logger::getLogger(__CLASS__)->info(__METHOD__ . ': realPathed: '.$realPath);
        $pathStartToCompare = substr($realPath, 0, strlen($baseAppPath));

        Logger::getLogger(__CLASS__)->info(__METHOD__ . ': Realpath: '. $realPath);
        Logger::getLogger(__CLASS__)->info(__METHOD__ . ': Path to compare with app base path: ' . $pathStartToCompare);

        //check that is within app root
        if(strcmp($pathStartToCompare, $baseAppPath) != 0) {
            $result = false;
        }
        
        return $result;
    }
}
?>
